 //module TESTER( clk, reset, ad, ready, test, intr, inta, nmi, hold, mnmx, // input
//               a, as, rd, wr, iom, ale, dtr, den, hlda, ss0, //output
//               t_3, t_8, t_16, t_20); // test
//
//	input clk,reset;	
//	inout [7:0] ad;	
//	input ready;	//ready pin, high means data ready 
//	input test;		//"wait for test" instruction, low enable 
//	input intr;		//interrupt request, high enable 
//	input inta;		//interrupt acknowledge, low enable
//	input nmi;		//non-maskable interrupt, posedge enable							 
//	input hold;		//indicate another master is requesting a local bus "hold", high enable
//	input mnmx;		//MINIMUM/MAXIMUM, high indicate minimum, low indicate maxmum
//
//	output [15:8] a;	//external a pins, 8 bits, address[15:8]
//	output [6:3] as;	//external as pins, 4 bits, address[19:16], state[6:3]
//	output rd;		//rd pin, low enable
//	output wr;		//wr pin, low enable
//	output iom;		//iom pin, high means memory access, low means io access
//	output ale;		//ale pin, high enable
//	output dtr;		//dtr pin, low means read, high means write
//	output den;		//den pin, low means data valid
//	output hlda;	//an acknowledge of hold request, high enable
//	output ss0;		//status line
//
//    output [2:0] t_3;
//    output [7:0] t_8;
//	output [15:0] t_16;
//	output [19:0] t_20;
//
//    //wire [19:0] bus_20;
//    //wire [15:0] bus_16;
//    //wire [11:0] bus_12;
//
//   IP8088 IP8088_mod( .clk(clk), .reset(reset), .ad(bus_ad), .a(bus_20[15:8]), .as(bus_20[19:16]), .rd(rd), .wr(wr),
//                      .iom(iom), .ale(ale), .dtr(dtr), .den(den), .ready(ready), .test(test), .intr(intr),
//                      .inta(inta), .nmi(nmi), .hold(hold), .hlda(hlda), .ss0(ss0), .mnmx(mnmx));
//
//   SRAM SRAM_mod( .address( bus_20[11:0]), .clock( clk), .data(8'b0),
//                  .wren(), .q(ad));
//
//endmodule

module IP8088( clk, reset, ad, a, as, rd, wr, 
               iom, ale, dtr, den, ready, test, 
               intr, inta, nmi, hold, hlda, ss0, mnmx,
               t_B_BUS, t_addr_unit, t_ir_unit, t_bus_ok,
               t_mtype, t_ir_ctrl, t_ir_whole,
               t_16);

    input clk,reset;	//clock and reset signal,clk rising edge enable,reset high enable
    inout [7:0] ad;		//external ad pins, 8 bits, address[7:0], data[7:0]
    output [15:8] a;	//external a pins, 8 bits, address[15:8]
    output [6:3] as;	//external as pins, 4 bits, address[19:16], state[6:3]
    output rd;		// /rd pin, low enable
    output wr;		// /wr pin, low enable
    output iom;		//iom pin, high means memory access, low means io access
    output ale;		//ale pin, high enable
    output dtr;		//dtr pin, low means read, high means write
    output den;		//den pin, low means data valid
    input ready;	//ready pin, high means data ready 
    input test;		//"wait for test" instruction, low enable 
    input intr;		//interrupt request, high enable 
    input inta;		//interrupt acknowledge, low enable
    input nmi;		//non-maskable interrupt, posedge enable							 
    input hold;		//indicate another master is requesting a local bus "hold", high enable
    output hlda;	//an acknowledge of hold request, high enable
    output ss0;		//status line
    input mnmx;		//MINIMUM/MAXIMUM, high indicate minimum, low indicate maxmum

    output [15:0] t_16;

    output [15:0] t_B_BUS;
    output [19:0] t_addr_unit;
    output  [7:0] t_ir_unit;

    output        t_bus_ok;
    output  [3:0] t_mtype;
    output  [1:0] t_ir_ctrl;
    output [15:0] t_ir_whole;
    
    assign t_B_BUS = _B_BUS;
    assign t_addr_unit = _addr_unit;
    assign t_ir_unit = _ir_unit;

    assign t_bus_ok = _bus_ok;
    assign t_mtype = _mtype;
    assign t_ir_ctrl = _ir_ctrl;
    assign t_ir_whole = _ir_whole;

    wire [15:0] _B_BUS;
    wire [19:0] _addr_unit;
    wire  [7:0] _ir_unit;
	wire        _ip_incre;

    wire        _bus_ok;
    wire  [3:0] _mtype;
    wire  [1:0] _ir_ctrl;
    wire [15:0] _ir_whole;

    IP IP_mod( .clk(clk), .reset(reset), .ipinen(1'b0), 
               .ipin(16'b0), .ipouten(1'b1), .ipout(_B_BUS), .ipinc(_ip_incre)
             //, .t_ip(t_16)
		      );
       
    MAR MAR_mod( .clk(clk), .reset(reset), .addr_in(_B_BUS), .addr_out(_addr_unit));

    IR IR_mod( .clk(clk), .reset(reset), .ir_high(_ir_ctrl[1]), .ir_low(_ir_ctrl[0]),
               .irin(_ir_unit), .irout(_ir_whole));

    CONTROL CONTROL_mod( .clk(clk), .reset(reset), .mtype(_mtype),
                         .ir_ctrl(_ir_ctrl), .ir(_ir_whole), .ip_incre(_ip_incre), 
                         .bus_ok(_bus_ok));

    BCL BCL_mod( .clk(clk), .reset(reset), .mtype(_mtype), .addrin(_addr_unit),
                 .ad(ad), .a(a), .as(as), .datain(_B_BUS), 
                 .re(rd), .we(wr), .iom(iom), .datatoir(_ir_unit), .ale(ale),
                 .dtr(dtr), .den(den), .ready(ready), .bus_ok(_bus_ok)
               , .t_buscycle(t_16[2:0])
                 );

endmodule 	

module MAR( clk, reset, addr_in, addr_out);

    input clk;
    input reset;
    input [15:0] addr_in;
    output [19:0] addr_out;

    reg [19:0] addr_out_r;
    assign addr_out = addr_out_r;

    always @ ( posedge clk)
    begin
        if ( reset)
        begin
            addr_out_r <= 20'b0;
        end
        else
            addr_out_r <= {4'b0,addr_in};
        begin
        end
    end

endmodule

module IR( clk, reset, ir_high, ir_low, irin, irout);

    input clk,reset;
    input [7:0] irin;
    input ir_high;
    input ir_low;

    output [15:0] irout;
    reg [15:0] irout_r;
    assign irout = irout_r;
    
    always @( posedge clk)
    begin
        if (reset)
        begin
            irout_r <= 16'b0;		
        end
        else if ( ir_high == 1'b1)
        begin
            irout_r[15:8] <= irin;
        end
        else if ( ir_low == 1'b1)
        begin
            irout_r[7:0] <= irin;
        end
        else
        begin
             //irout_r <= 16'b0;
            irout_r <= irout_r;
        end
    end

endmodule

module CONTROL( clk, reset, mtype, ir_ctrl, ir, ip_incre, bus_ok);

    input reset,clk;
    input [15:0] ir;
    input bus_ok;

    output [3:0] mtype;
    output [1:0] ir_ctrl;
    output ip_incre;

    reg [2:0] control_state;

    reg ip_incre_r;
    assign ip_incre = ip_incre_r;
    
    reg [3:0] mtype_r;
    assign mtype = mtype_r;

    reg ir_high_r;
    assign ir_ctrl[1] = ir_high_r;

    reg ir_low_r;
    assign ir_ctrl[0] = ir_low_r;

    always @ ( posedge clk)
    begin
        if (reset)
        begin
            control_state <= 3'b0; 
            mtype_r <= 4'b1000;
            ip_incre_r <= 1'b0;
		    ir_low_r <= 1'b0;	
		    ir_high_r <= 1'b0;	
        end
        else
        begin
            casex (control_state)
                // Fetch Instruction
                3'b000:
                begin
                    if ( bus_ok == 1'b1)
                    begin
                        ir_high_r <= 1'b1; 
                        ip_incre_r <= 1'b1;
                        control_state <= 3'b001;
                        mtype_r <= 4'b0000;
                    end
                    else
                    begin
                        mtype_r <= 4'b1000;
                    end
                end
                // Fetch more when necessary
                3'b001:
                begin
                    ir_high_r <= 1'b0;
                    ip_incre_r <= 1'b0;
                    control_state <= 3'b010;
                end
                // Get data
                3'b010:
                begin
                    ir_low_r <= 1'b0; 
                    control_state <= 3'b011;
                    ip_incre_r <= 1'b0;
                end
                // execute
                3'b011:
                begin
                    control_state <= 3'b100;
                end
                // write
                3'b100:
                begin
                    control_state <= 3'b000;
                    mtype_r <= 4'b1000;
                end
            endcase
        end
    end

endmodule

module IP(clk,reset,ipinen,ipin,ipouten,ipout,ipinc,t_ip); 

    input clk,reset;	//clock and reset signal,clk rising edge enable,reset high enable							 
    input ipinen;	//control bit of ip input
    input [15:0] ipin;	//data of ip input
    // ### linked with B-BUS ###
    input ipouten;		//control bit of ip output
    output [15:0] ipout;	//data of ip output
    // ### linke with B-BUS ###
    input ipinc;	//control bit of ip increment
    output [15:0] t_ip;
    assign t_ip = ipreg;	 

    reg [15:0] ipreg;

    assign ipout = (!reset&&ipouten)? ipreg: 16'bz;

    always @(posedge clk)
    begin 
        if (reset) ipreg <= 0;		//start at 0x0000
        else begin 
            if (ipinen) ipreg <= ipin;
            if (ipinc) ipreg <= ipreg + 1;
        end
    end

endmodule

module BCL( clk, reset, mtype, addrin, ad, a, as, datain,
    re, we, iom, datatoir, ale, dtr, den, ready, bus_ok,
    t_buscycle);
/*
control how to interact with memory or io system
*/

    input clk,reset;	//clock and reset signal,clk rising edge enable,reset high enable

    input [3:0] mtype;	//control how to do

    input [19:0] addrin;	//input address,will send to external address bus

    inout [7:0] ad;		//address data multi-wires, address[7:0], data[7:0]
    //### linked with ad ###					
    output [15:8] a;	//address wires only, address[15:8]
    //### linked with a ###
    output [6:3] as;	//address state multi-wires,address[19:16] 
    //### linked with as ###
    inout [15:0] datain;	//data to interact with internal data bus
    // ### linked with B_BUS ###
    output re;		//control bit of read signal
    //### linked with re ###
    output we;		//control bit of write signal
    //### linked with we ###
    output iom;		//control bit of io access or memory access
    //### linked with iom ###
    output [7:0] datatoir; 	//instruction data for instruction registers
    //### linked with IR ###
    output ale;		//control bit of address output signal
    //### linked with ale ###
    output dtr;		//control bit of data direction
    //### linked with dtr ###
    output den;	 	//control bit of data signals
    //### linked with den ###
    input ready;	//### linked with ready ###

    output bus_ok;

    output [2:0] t_buscycle;

    reg [2:0] buscycle;		//two bits' state to cooperate with external bus

    assign t_buscycle = buscycle;

    reg [7:0] ad;	//ad
    reg [15:8] a;	//a
    reg [6:3] as;	//as
    reg ale;	//ale
    reg re;		//re
    reg we;		//wr
    reg iom;    //iom
    reg dtr;	//dtr
    reg den;	//den
    reg [7:0] datatoir_r;	//datatoir
    reg [15:0] datain_r;	//datain
    reg bus_ok;

    assign datatoir = datatoir_r;
    assign datain = datain_r;

    always @(posedge clk)
    begin 
        if (reset)
        begin 
			buscycle <= 3'b000;
			{as,a,ad} <= 20'bz;
			re <= 1'b1;
			we <= 1'b1;
			iom <= 1'b0;
			ale <= 1'b1;//change by from 1'b0 bydfliu in 2009_5_1
			datatoir_r <= 8'bz;
			datain_r <= 16'bz;
			bus_ok <= 1'b0;
        end
        else if ( mtype[3] == 1'b1) // necessary to access the bus
        /*
            mtype                function
            0xxx                 invalid
            1000                 mem-->ir
        */
        begin
            casex (buscycle)
                3'b000:
                begin
                    casex (mtype)
                        4'b1000: begin
                            // address on the external bus
                            {as,a,ad} <= addrin[11:0];
                            iom <= 1'b1;
                        end
                    endcase
                    //re <= 1'b0;
                    we <= 1'b1;
                    bus_ok <= 1'b0;
                    ale <= 1'b0;//change bydfliu in 2009_5_1
                    buscycle <= 3'b001;	//next bus cycle
                end
                3'b001:
                begin 		
                bus_ok <= 1'b0;
                buscycle <= 3'b010; 	//next cycle
                casex (mtype)
                    4'b1000: begin
                        //ale <= 1'b1;//change bydfliu in 2009_5_1
                        re <= 1'b0; // read
                        ad <= 8'bz; //add bydfliu in 2009_5_1
                    end
                endcase
                end
                3'b010:
                    if ( ready)
                    begin
                        ale <= 1'b1;//change bydfliu in 2009_5_1
                        buscycle <= 3'b011;	
                        casex (mtype)
                        4'b1000: begin
                            //{as,a,ad} <= 20'bz;
                            datatoir_r <= ad;
                            //datain_r <= 16'bz;
                        end
                    endcase
                    bus_ok <= 1'b1;						    
                    end
                3'b011: 
                begin
//                    casex (mtype)
//                        4'b1000: begin
//                            //{as,a,ad} <= 20'bz;
//                            datatoir_r <= ad;
//                            //datain_r <= 16'bz;
//                        end
//                    endcase	
                    bus_ok <= 1'b0;	
                    re <= 1'b1;
                    //buscycle <= 3'b100;	
                    buscycle <=3'b000;
                    //
                end
            endcase		
        end // else if mtype[3]
        else
        begin 
            datain_r <= 16'bz;
            buscycle <= 3'b000;
        end
    end

endmodule
